/*
*  Copyright (c) 2001 Sun Microsystems, Inc.  All rights
*  reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  1. Redistributions of source code must retain the above copyright
*  notice, this list of conditions and the following disclaimer.
*
*  2. Redistributions in binary form must reproduce the above copyright
*  notice, this list of conditions and the following discalimer in
*  the documentation and/or other materials provided with the
*  distribution.
*
*  3. The end-user documentation included with the redistribution,
*  if any, must include the following acknowledgment:
*  "This product includes software developed by the
*  Sun Microsystems, Inc. for Project JXTA."
*  Alternately, this acknowledgment may appear in the software itself,
*  if and wherever such third-party acknowledgments normally appear.
*
*  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
*  must not be used to endorse or promote products derived from this
*  software without prior written permission. For written
*  permission, please contact Project JXTA at http://www.jxta.org.
*
*  5. Products derived from this software may not be called "JXTA",
*  nor may "JXTA" appear in their name, without prior written
*  permission of Sun.
*
*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
*  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
*  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
*  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*  SUCH DAMAGE.
*  ====================================================================
*
*  This software consists of voluntary contributions made by many
*  individuals on behalf of Project JXTA.  For more
*  information on Project JXTA, please see
*  <http://www.jxta.org/>.
*
*  This license is based on the BSD license adopted by the Apache Foundation.
*
*  $Id: URIFilter.java,v 1.5 2007/05/23 21:00:17 nano Exp $
*/

package net.jxta.myjxta.dialog.filter;

import net.jxta.myjxta.dialog.DialogMessage;
import net.jxta.myjxta.dialog.DialogMessageWrapper;

import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Creates HTML anchor tags for URI text.<br>
 * Protocols that are processed are:  http, https, ftp, mailto, file, news, telnet, gopher, feed and urn.
 *
 * @author mike mcangus [mcangus at jxta dot org]
 * @version $Id: URIFilter.java,v 1.5 2007/05/23 21:00:17 nano Exp $
 */

public class URIFilter extends AbstractDialogFilter {

    private static final Logger LOG = Logger.getLogger(URIFilter.class.getName());
    private static final String[] protocols =
            {"http://", "https://", "ftp://", "mailto:", "file://", "news:", "telnet://", "gopher://", "feed:", "urn:"};

    private static final String ANCHOR_START = "<a href=\"";
    private static final String ANCHOR_CLOSE = "\">";
    private static final String ANCHOR_END = "</a>";

    private static final ArrayList<Pattern> patternList = new ArrayList<Pattern>();

    static {
        Pattern pattern = null;
        for (int i = 0; i < protocols.length; i++) {
            pattern = Pattern.compile(protocols[i] + "([^)\"<\\s]+)", Pattern.CASE_INSENSITIVE);
            patternList.add(pattern);
        }
    }

    /**
     * Finds URI seqences in the message text, and surrounds those sequences with the HTML anchor tag &lt;a&gt;.
     * Uses {@link java.util.regex.Pattern regex Pattern} and {@link java.util.regex.Matcher regex Matcher}
     * to find URI sequences and to perform the substitutions.
     *
     * @param msg the newly received DialogMessage object
     * @return the newly modified DialogMessage object.
     * @see net.jxta.myjxta.dialog.DialogFilter#filter(net.jxta.myjxta.dialog.DialogMessage)
     */
    public DialogMessage filter(DialogMessage msg) {
        if (!processMessage((DialogMessageWrapper) msg)) {
            return msg;
        }

        LOG.log(java.util.logging.Level.FINE, "Begin filter(DialogMessage)");

        String msgText = msg.getHtmlMessage();

        if (msgText != null && msgText.trim().length() > 0) {
            Pattern pattern = null;
            Matcher matcher = null;
            int patMax = patternList.size();
            for (int i = 0; i < patMax; i++) {
                pattern = patternList.get(i);
                matcher = pattern.matcher(msgText);
                boolean matchFound = matcher.find();

                int start = -1;
                int end = -1;
                int prevEnd = 0;
                String uri = null;
                StringBuffer msgBuff = new StringBuffer();

                if (matchFound) {
                    while (matchFound) {
                        start = matcher.start();
                        end = matcher.end();
                        msgBuff.append(msgText.substring(prevEnd, start));
                        uri = matcher.group();
                        if (uriAlreadyTagged(msgText, prevEnd, start, end)) {
                            msgBuff.append(uri);
                        } else {
                            msgBuff.append(ANCHOR_START)
                                    .append(uri)
                                    .append(ANCHOR_CLOSE)
                                    .append(uri)
                                    .append(ANCHOR_END);
                        }
                        prevEnd = end;
                        matchFound = matcher.find();
                    }
                    if ((prevEnd > -1) && (prevEnd < msgText.length())) {
                        msgBuff.append(msgText.substring(prevEnd));
                    }
                    msgText = msgBuff.toString();
                }
            }
            msg.setHtmlMessage(msgText);
        }

        LOG.log(java.util.logging.Level.FINE, "End   filter(DialogMessage)");
        return msg;
    }

    /**
     * Deterimines whether or not the matched URI string is preceeded by a tag with an "href = " attribute.
     * <p/>
     * We expect a tagged URI to be of the form: <code>
     * <pre>
     *     <tag attr1="value1" attr2="value2" ... uriAttr="URI" attrN="valueN" attrN1="valueN1" attrN2="valueN2" ... >
     * </pre>
     * where all attribute/value pairs are optional except the uriAttr="URI" pair.
     *
     * @param msgText   The text containing the found URI
     * @param scanStart The end of the previous search, if any.
     * @param uriStart  The start of the found URI.
     * @param uriEnd    One character beyond the end of the found URI.
     * @return true if the URI is part of a tag, and false otherwise.
     */
    private boolean uriAlreadyTagged(String msgText, int scanStart, int uriStart, int uriEnd) {
        // TODO Make this more robust.  There are still many ways that a URI could be kept from displaying as a link.
        uriEnd--;
        int tagStart = msgText.indexOf('<', scanStart);
        int equalStart = msgText.indexOf('=', tagStart);
        int quoteStart = msgText.indexOf('"', equalStart);
        int quoteEnd = msgText.indexOf('"', uriEnd);
        int tagEnd = msgText.indexOf('>', quoteEnd);
        if ((tagStart > -1) && (tagStart < uriStart) &&
                (equalStart > -1) && (equalStart < uriStart) &&
                (quoteStart > -1) && (quoteStart < uriStart) &&
                (quoteEnd > -1) && (quoteEnd >= uriEnd) &&
                (tagEnd > -1)
                ) {
            return true;
        }
        return false;
    }
}
